Skip to content

fix: clear key mismatch warning after successful purge resolution (#2349)#2365

Merged
Yeraze merged 1 commit intomainfrom
fix/key-mismatch-persistent-warning
Mar 21, 2026
Merged

fix: clear key mismatch warning after successful purge resolution (#2349)#2365
Yeraze merged 1 commit intomainfrom
fix/key-mismatch-persistent-warning

Conversation

@Yeraze
Copy link
Copy Markdown
Owner

@Yeraze Yeraze commented Mar 21, 2026

Summary

Fixes #2349 — the key mismatch warning persisted indefinitely even after a successful key exchange.

Root Cause

After a successful immediate purge + NodeInfo exchange:

  1. The device re-syncs and updates the stored key to match the mesh-received key
  2. Next time mesh NodeInfo arrives, existingNode.publicKey === nodeData.publicKey (keys match), so the mismatch detection block at line 4311 is skipped
  3. The clearing block at line 4362 runs, but oldKey !== newKey is false (keys already match), so it never clears the flag
  4. keyMismatchDetected stays true forever in the database

Fix

Remove the oldKey !== newKey gate on the clearing block. If keyMismatchDetected is true and we're not seeing a new mismatch, clear it regardless — keys matching means the mismatch is resolved.

Files Changed

File Change
src/server/meshtasticManager.ts Clear keyMismatchDetected when keys match (post-purge) in addition to when a new key arrives

Test plan

  • 3052 tests pass, 0 failures
  • Logic handles both resolution paths: new key arrives (oldKey !== newKey) and keys stabilized (oldKey === newKey)

🤖 Generated with Claude Code

#2349)

After a successful purge + NodeInfo exchange, the stored key gets updated
to match the mesh-received key. But the clearing block only fired when
oldKey !== newKey, so the keyMismatchDetected flag persisted forever when
keys already matched (post-purge scenario).

Now clears the flag in both cases: when a new key arrives AND when keys
already match (indicating the mismatch was resolved via device re-sync).

Closes #2349

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
}

// Existing block — only runs for PKI-error-based mismatches, NOT our proactive detection
// Clear mismatch flag when keys now match (post-purge resolution)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Excellent improvement to the comment clarity. This clearly explains both resolution scenarios that the code now handles.

Comment on lines 4368 to 4375
if (oldKey !== newKey) {
// Key has changed - the mismatch is fixed!
// Key has changed - the mismatch is fixed via new key
logger.info(`🔐 Key mismatch RESOLVED for node ${nodeId} (${user.longName}) - received new key`);
nodeData.keyMismatchDetected = false;
nodeData.lastMeshReceivedKey = undefined;
// Don't clear keySecurityIssueDetails if there's a low-entropy issue
if (!isLowEntropy) {
nodeData.keySecurityIssueDetails = undefined;
}

// Clear the repair state and log success
databaseService.clearKeyRepairStateAsync(fromNum);
const nodeName = user.longName || user.shortName || nodeId;
databaseService.logKeyRepairAttemptAsync(fromNum, nodeName, 'fixed', true);
} else {
// Keys now match - the mismatch was fixed (e.g., device re-synced after purge)
logger.info(`🔐 Key mismatch RESOLVED for node ${nodeId} (${user.longName}) - keys now match`);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Perfect fix for the core issue

This is the critical change that resolves #2349. The previous logic had a gap:

Before: Only cleared keyMismatchDetected when oldKey !== newKey (new key scenario)
After: Clears the flag for both scenarios - when a new key arrives AND when keys already match

The else branch handling oldKey === newKey is exactly what was missing. After a successful immediate purge + NodeInfo exchange, the device re-syncs and the keys match, but the old logic would skip clearing the flag entirely.

The solution correctly handles both resolution paths while maintaining appropriate logging for each case.

Comment on lines +4376 to 4393
nodeData.keyMismatchDetected = false;
nodeData.lastMeshReceivedKey = undefined;
// Don't clear keySecurityIssueDetails if there's a low-entropy issue
if (!isLowEntropy) {
nodeData.keySecurityIssueDetails = undefined;
}

// Clear the repair state and log success
databaseService.clearKeyRepairStateAsync(fromNum);
const nodeName = user.longName || user.shortName || nodeId;
databaseService.logKeyRepairAttemptAsync(fromNum, nodeName, 'fixed', true);

// Emit update to UI
dataEventEmitter.emitNodeUpdate(fromNum, {
keyMismatchDetected: false,
keySecurityIssueDetails: isLowEntropy ? nodeData.keySecurityIssueDetails : undefined
});
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good refactoring: Moving the common cleanup code outside the conditional ensures it runs for both resolution scenarios. This eliminates the duplication that would have been needed and ensures consistent state cleanup regardless of how the mismatch was resolved.

@Yeraze Yeraze merged commit d07eb51 into main Mar 21, 2026
17 checks passed
Yeraze added a commit that referenced this pull request Mar 22, 2026
PKI_UNKNOWN_PUBKEY and PKI_SEND_FAIL_PUBLIC_KEY routing errors were
suppressed when the target node wasn't in the radio's device database.
The guard assumed this was only expected after factory reset/purge,
but it also suppressed legitimate key mismatch detection for nodes
the radio simply doesn't know about.

Removed the isNodeInDeviceDb() guard from both routing error paths
(request packets and message-tracked packets). The key mismatch flag
will now clear naturally via the resolution logic in PR #2365 when
keys are re-synced.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Yeraze added a commit that referenced this pull request Mar 22, 2026
* fix: PKI_UNKNOWN_PUBKEY errors now correctly flag key mismatch

PKI_UNKNOWN_PUBKEY and PKI_SEND_FAIL_PUBLIC_KEY routing errors were
suppressed when the target node wasn't in the radio's device database.
The guard assumed this was only expected after factory reset/purge,
but it also suppressed legitimate key mismatch detection for nodes
the radio simply doesn't know about.

Removed the isNodeInDeviceDb() guard from both routing error paths
(request packets and message-tracked packets). The key mismatch flag
will now clear naturally via the resolution logic in PR #2365 when
keys are re-synced.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* test+docs: add PKI error detection tests and architecture documentation

- 9 new tests for isPkiError, RoutingError constants, getPortNumName
- Document PKI error detection rules in ARCHITECTURE_LESSONS.md
- Anti-pattern: never gate PKI detection on isNodeInDeviceDb()

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] 3.9.5 - Message still persistent even after key exchange is successfuly completed.

1 participant